#include <sample-grabber.hpp>
#ifdef WIN32

#define RGB3 ('R' | ('G' << 8) | ('B' << 16) | ('3' << 24))

static inline unsigned char
clamp(unsigned char X)
{
    unsigned char x = abs(X);

    if (x > 255) x = 255;
    return x;
}

SampleGCB::SampleGCB()
{
    InitializeCriticalSection(&cSection);

    imgdata   = NULL;
    width     = 0;
    height    = 0;
    nBytes    = 0;
    inverted  = false;
    fps       = 0;
    last      = clock();
}

SampleGCB::~SampleGCB()
{
    DeleteCriticalSection(&cSection);
    if (imgdata)
        free(imgdata);
}

void
SampleGCB::negate()
{
    inverted = !inverted;
}

void
SampleGCB::copyBitsRGB(unsigned char *pixels)
{
    EnterCriticalSection(&cSection);

    long            stride;
    long            nB;
    unsigned char   *aux;
    int             i;
    int             j;

    stride = 3 * width;
    nB     = stride * height;

    if (nB > nBytes)
        return;

    aux = (unsigned char *)realloc(imgdata, nBytes);
    if (aux) {
        imgdata = aux;
        pixels += height * stride;
        if (inverted) {
            for (i = 0 ; i < height ; i++) {
                pixels -= stride;
                for (j = 0 ; j < width ; j++) {
                    *(aux++) = 255 - *(pixels + 2);
                    *(aux++) = 255 - *(pixels + 1);
                    *(aux++) = 255 - *(pixels);
                    pixels  += 3;
                }
                pixels -= stride;
            }
        } else {
            for (i = 0 ; i < height ; i++) {
                pixels -= stride;
                for (j = 0 ; j < width ; j++) {
                    *(aux++) = *(pixels + 2);
                    *(aux++) = *(pixels + 1);
                    *(aux++) = *(pixels);
                    pixels  += 3;
                }
                pixels -= stride;
            }
        }
    }
    LeaveCriticalSection(&cSection);
}

double
SampleGCB::getFPS()
{
    return fps;
}

HRESULT
SampleGCB::BufferCB(double, BYTE *ptr, long nB)
{
    nBytes = nB;
    if (nB > 0) {
        copyBitsRGB(ptr);

        /* Calcular FPS */
        time_t now;

        now  = clock();
        fps  = ((double)CLOCKS_PER_SEC / (double)(now - last) + fps) / 2.0;
        last = now;

        /* Enviar el cuadro */
        emit sendFrame(ptr, width, height, 3 * width, RGB3, nBytes);
    }
    return S_OK;
}

HRESULT
SampleGCB::QueryInterface(REFIID, void **ppvObject)
{
    *ppvObject = static_cast<ISampleGrabberCB *>(this);
    return S_OK;
}

void
SampleGCB::setSize(uint _w, uint _h)
{
    EnterCriticalSection(&cSection);

    width  = _w;
    height = _h;

    LeaveCriticalSection(&cSection);
}

HRESULT
SampleGCB::SampleCB(double, IMediaSample *smpl)
{
    return E_NOTIMPL;
}

ULONG
SampleGCB::AddRef()
{
    return 0;
}

ULONG
SampleGCB::Release()
{
    delete this;
    return 0;
}
#endif
